home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / internet / other / ka9q / ka9q_src.arc / TCPOUT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1988-07-28  |  5.0 KB  |  174 lines

  1. #include "global.h"
  2. #include "timer.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "internet.h"
  6. #include "tcp.h"
  7.  
  8. /* Send a segment on the specified connection. One gets sent only
  9.  * if there is data to be sent or if "force" is non zero
  10.  */
  11. void
  12. tcp_output(tcb)
  13. register struct tcb *tcb;
  14. {
  15.     struct pseudo_header ph;/* Pseudo-header for checksum calcs */
  16.     struct mbuf *hbp,*dbp;    /* Header and data buffer pointers */
  17.     int16 hsize;        /* Size of header */
  18.     struct tcp seg;        /* Local working copy of header */
  19.     int16 ssize;        /* Size of current segment being sent,
  20.                  * including SYN and FIN flags */
  21.     int16 dsize;        /* Size of segment less SYN and FIN */
  22.     int16 usable;        /* Usable window */
  23.     int16 sent;        /* Sequence count (incl SYN/FIN) already in the pipe */
  24.  
  25.     if(tcb == NULLTCB)
  26.         return;
  27.  
  28.     switch(tcb->state){
  29.     case LISTEN:
  30.     case CLOSED:
  31.         return;    /* Don't send anything */
  32.     }
  33.     for(;;){
  34.         sent = tcb->snd.ptr - tcb->snd.una;
  35.  
  36.         /* If this is a retransmission, send only the oldest segment
  37.          * (first-only retransmission policy)
  38.          */
  39.         if((tcb->flags & RETRAN) && sent != 0)
  40.             break;
  41.  
  42.         /* There can only be one outstanding segment in this state
  43.          * since the other end would reject any segment without SYN
  44.          */
  45.         if(tcb->state == SYN_SENT && sent != 0)
  46.             break;
  47.         if(tcb->snd.wnd == 0){
  48.             /* Allow only one closed-window probe at a time */
  49.             if(sent != 0)
  50.                 break;
  51.             /* Force a closed-window probe */
  52.             usable = 1;
  53.         } else {
  54.             /* usable window = offered window - unacked bytes in transit */
  55.             usable = tcb->snd.wnd - sent;
  56.  
  57.             /* John Nagle's "single outstanding segment" rule.
  58.              * Allow only one segment in the pipeline unless there is enough
  59.              * unsent data to form at least one maximum-sized segment.
  60.              */
  61.             if(sent != 0 && tcb->sndcnt - sent < tcb->mss){
  62.                 usable = 0;
  63.             }
  64.             /* Silly window avoidance. Don't send anything if the usable window
  65.              * is less than a quarter of the offered window.
  66.              * This test comes into play only when the offered window is at
  67.              * least 4 times the MSS; otherwise Nagle's test is sufficient
  68.              * to prevent SWS.
  69.               */
  70.             else if(usable < tcb->snd.wnd/4){
  71.                 usable = 0;
  72.             }
  73.         }
  74.         /* Compute size of segment to send. This is either the usable
  75.          * window, the mss, or the amount we have on hand, whichever is less.
  76.          * (I don't like optimistic windows)
  77.          */
  78.         ssize = min(tcb->sndcnt - sent,usable);
  79.         ssize = min(ssize,tcb->mss);
  80.         dsize = ssize;
  81.  
  82.         if(ssize == 0 && !(tcb->flags & FORCE))
  83.             break;        /* No need to send anything */
  84.  
  85.         tcb->flags &= ~FORCE;    /* Only one forced segment! */
  86.  
  87.         seg.source = tcb->conn.local.port;
  88.         seg.dest = tcb->conn.remote.port;
  89.  
  90.         /* Set the SYN and ACK flags according to the state we're in. It is
  91.          * assumed that if this segment is associated with a state transition,
  92.          * then the state change will already have been made. This allows
  93.          * this routine to be called from a retransmission timeout with
  94.          * force=1.
  95.          * If SYN is being sent, adjust the dsize counter so we'll
  96.          * try to get the right amount of data off the send queue.
  97.          */
  98.         seg.flags = ACK; /* Every state except SYN_SENT */
  99.         hsize = TCPLEN;    /* Except when SYN being sent */
  100.         seg.mss = 0;
  101.  
  102.         switch(tcb->state){
  103.         case SYN_SENT:
  104.             seg.flags = 0;    /* Note fall-thru */
  105.         case SYN_RECEIVED:
  106.             if(tcb->snd.ptr == tcb->iss){
  107.                 seg.flags |= SYN;
  108.                 dsize--;
  109.                 /* Also send MSS */
  110.                 seg.mss = tcp_mss;
  111.                 hsize = TCPLEN + MSS_LENGTH;
  112.             }
  113.             break;
  114.         }
  115.         seg.seq = tcb->snd.ptr;
  116.         seg.ack = tcb->rcv.nxt;
  117.         seg.wnd = tcb->rcv.wnd;
  118.         seg.up = 0;
  119.  
  120.         /* Now try to extract some data from the send queue.
  121.          * Since SYN and FIN occupy sequence space and are reflected
  122.          * in sndcnt but don't actually sit in the send queue,
  123.          * dup_p will return one less than dsize if a FIN needs to be sent.
  124.          */
  125.         if(dsize != 0){
  126.             if(dup_p(&dbp,tcb->sndq,sent,dsize) != dsize){
  127.                 /* We ran past the end of the send queue; send a FIN */
  128.                 seg.flags |= FIN;
  129.                 dsize--;
  130.             }
  131.         } else
  132.             dbp = NULLBUF;
  133.  
  134.         /* If the entire send queue will now be in the pipe, set the
  135.          * push flag
  136.          */
  137.         if(dsize != 0 && sent + ssize == tcb->sndcnt)
  138.             seg.flags |= PSH;
  139.  
  140.         tcb->snd.ptr += ssize;
  141.         /* If this is the first transmission of a range of sequence
  142.          * numbers, record it so we'll accept acknowledgments
  143.          * for it later
  144.          */
  145.         if(seq_gt(tcb->snd.ptr,tcb->snd.nxt))
  146.             tcb->snd.nxt = tcb->snd.ptr;
  147.  
  148.         /* Fill in fields of pseudo IP header */
  149.         ph.source = tcb->conn.local.address;
  150.         ph.dest = tcb->conn.remote.address;
  151.         ph.protocol = TCP_PTCL;
  152.         ph.length = hsize + dsize;
  153.  
  154.         /* Generate TCP header, compute checksum, and link in data */
  155.         hbp = htontcp(&seg,dbp,&ph);
  156.  
  157.         /* If we're sending some data or flags, start retransmission
  158.          * and round trip timers if they aren't already running.
  159.          */
  160.         if(ssize != 0){
  161.             if(tcb->timer.state != TIMER_RUN){
  162.                 start_timer(&tcb->timer);
  163.             }
  164.             /* If round trip timer isn't running, start it */
  165.             if(!run_timer(&tcb->rtt_timer)){
  166.                 start_timer(&tcb->rtt_timer);
  167.                 tcb->rttseq = tcb->snd.ptr;
  168.             }
  169.         }
  170.         ip_send(tcb->conn.local.address,tcb->conn.remote.address,
  171.          TCP_PTCL,tcb->tos,0,hbp,ph.length,0,0);
  172.     }
  173. }
  174.